import type { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import type { Cluster, Redis } from "ioredis";

type ExtraData = Record<string, unknown>;

interface DocItem {
  id: string;
  rvn: string;
  lease: number;
  expires_at: number;
}

interface BaseClientConfig {
  lease: number;
  ttl?: number;
  client_name?: string;
}

interface DynamoDbSvcConfig extends BaseClientConfig {
  dynamodb: DynamoDBClient;
  table_name: string;
}

interface RedisSvcConfig extends BaseClientConfig {
  redis: Cluster | Redis;
  key_prefix?: string;
}

type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type Xor<T, U> = (T | U) extends object ? T & Without<U, T> | U & Without<T, U> : T | U;
type ClientConfig = Xor<DynamoDbSvcConfig, RedisSvcConfig> & {
  heartbeat?: number;
};

interface DistributedLock {
  release: () => Promise<void>;
}

interface DbService {
  getItem: (id: string) => Promise<DocItem | null>;
  createNewLock: (id: string, extra_data?: ExtraData) => Promise<string | null>;
  grabLock: (id: string, rvn: string, extra_data?: ExtraData) => Promise<string | null>;
  sendHeartBeat: (id: string, rvn: string) => Promise<string | null>;
  releaseLock: (id: string, rvn: string) => Promise<void>;
}

export {
  ExtraData, DocItem, DynamoDbSvcConfig, DistributedLock,
  DbService, RedisSvcConfig, ClientConfig
};
